using System;
using System.Collections.Generic;
using OracleInternal.Network;

namespace OracleInternal.TTC
{
	internal class OraBufReader
	{
		private OraBufWriter m_oraBufWriter;

		private ReaderStream m_readerStream;

		internal OraBuf m_currentOB;

		internal OraArraySegment[] m_currentArrSegments;

		internal int m_segmentCount;

		private OraArraySegment m_currentSegment;

		internal int m_currentSegmentIndex;

		internal byte[] m_currentSegmentArray;

		internal int m_positionInCurrentSegment;

		private byte[] m_tempOneByte = new byte[1];

		internal List<ArraySegment<byte>> m_dataSegments;

		internal List<OraBuf> m_tempOBList = new List<OraBuf>();

		internal long m_DataLeftInCurrentSegment;

		internal bool m_bAccumulateByteSegments;

		internal bool m_bParsingColumnData;

		internal bool m_bMarkStartOffsetForColData;

		internal int m_colDataStartOffsetIndexToUpdate = -1;

		internal int[] m_colDataStartOffset;

		internal int[] m_indexOfOASArray;

		internal OraArraySegment[] m_oraArrSegWithColRowInfo;

		internal int m_oraArrSegWithColRowInfoIndex;

		internal bool m_bHoldOBTemporarily;

		internal OraBufReader(ReaderStream rdrStream, OraBufWriter obWriter)
		{
			m_readerStream = rdrStream;
			m_oraBufWriter = obWriter;
		}

		internal void ClearState()
		{
			m_currentArrSegments = null;
			m_segmentCount = 0;
			m_currentSegment = null;
			m_currentSegmentIndex = -1;
			m_currentSegmentArray = null;
			m_dataSegments = null;
			m_positionInCurrentSegment = 0;
			m_bHoldOBTemporarily = false;
			m_DataLeftInCurrentSegment = 0L;
			m_bParsingColumnData = false;
			m_bMarkStartOffsetForColData = false;
			m_colDataStartOffsetIndexToUpdate = -1;
			m_colDataStartOffset = null;
			m_indexOfOASArray = null;
			m_oraArrSegWithColRowInfo = null;
			m_oraArrSegWithColRowInfoIndex = 0;
		}

		internal void FreeTempOBList()
		{
			for (int i = 0; i < m_tempOBList.Count; i++)
			{
				m_tempOBList[i].ReturnToPool();
			}
			m_tempOBList.Clear();
		}

		internal int Read(bool bIgnoreData = false)
		{
			int result = 0;
			if (m_DataLeftInCurrentSegment <= 0 && !DataAvailableInOraBuf())
			{
				GetDataFromNetwork();
			}
			if (m_bMarkStartOffsetForColData)
			{
				m_bMarkStartOffsetForColData = false;
				if (!m_currentSegment.m_bInUseByTTCLayer)
				{
					if (m_oraArrSegWithColRowInfo.Length <= m_oraArrSegWithColRowInfoIndex)
					{
						OraArraySegment[] array = new OraArraySegment[m_oraArrSegWithColRowInfo.Length * 2];
						for (int i = 0; i < m_oraArrSegWithColRowInfoIndex; i++)
						{
							array[i] = m_oraArrSegWithColRowInfo[i];
						}
						m_oraArrSegWithColRowInfo = array;
					}
					m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++] = m_currentSegment;
					m_currentOB = null;
					m_currentSegment.m_bInUseByTTCLayer = true;
				}
				m_colDataStartOffset[m_colDataStartOffsetIndexToUpdate] = m_positionInCurrentSegment;
				m_indexOfOASArray[m_colDataStartOffsetIndexToUpdate] = m_oraArrSegWithColRowInfoIndex - 1;
			}
			if (!bIgnoreData)
			{
				result = m_currentSegmentArray[m_positionInCurrentSegment] & 0xFF;
			}
			m_positionInCurrentSegment++;
			m_DataLeftInCurrentSegment--;
			return result;
		}

		internal int Read(byte[] userBuffer)
		{
			return Read(userBuffer, 0, userBuffer.Length);
		}

		internal int Read(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			do
			{
				if (m_DataLeftInCurrentSegment <= 0 && !DataAvailableInOraBuf())
				{
					GetDataFromNetwork();
				}
				num += GetData(userBuffer, offset + num, length - num);
			}
			while (num < length);
			return num;
		}

		internal bool ReadLengthAndData(byte repOffset, byte typeRep, out byte[] dataBuffer, ref int offset, ref int bufLength, bool IgnoreData = false)
		{
			bool result = false;
			if ((typeRep & 1) > 0)
			{
				if (m_DataLeftInCurrentSegment <= 0 && !DataAvailableInOraBuf())
				{
					GetDataFromNetwork();
				}
				if (m_bMarkStartOffsetForColData)
				{
					m_bMarkStartOffsetForColData = false;
					if (!m_currentSegment.m_bInUseByTTCLayer)
					{
						if (m_oraArrSegWithColRowInfo.Length <= m_oraArrSegWithColRowInfoIndex)
						{
							OraArraySegment[] array = new OraArraySegment[m_oraArrSegWithColRowInfo.Length * 2];
							for (int i = 0; i < m_oraArrSegWithColRowInfoIndex; i++)
							{
								array[i] = m_oraArrSegWithColRowInfo[i];
							}
							m_oraArrSegWithColRowInfo = array;
						}
						m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++] = m_currentSegment;
						m_currentOB = null;
						m_currentSegment.m_bInUseByTTCLayer = true;
					}
					m_colDataStartOffset[m_colDataStartOffsetIndexToUpdate] = m_positionInCurrentSegment;
					m_indexOfOASArray[m_colDataStartOffsetIndexToUpdate] = m_oraArrSegWithColRowInfoIndex - 1;
				}
				bufLength = m_currentSegmentArray[m_positionInCurrentSegment] & 0xFF;
				m_positionInCurrentSegment++;
				m_DataLeftInCurrentSegment--;
				if ((bufLength & 0x80) > 0)
				{
					bufLength &= 127;
					result = true;
				}
				if (bufLength < 0)
				{
					throw new Exception("TTC Error");
				}
				if (bufLength == 0)
				{
					dataBuffer = null;
					bufLength = 0;
					return result;
				}
				if ((repOffset == 1 && bufLength > 2) || (repOffset == 2 && bufLength > 4) || (repOffset == 3 && bufLength > 8))
				{
					throw new Exception("TTC Error");
				}
			}
			else
			{
				switch (repOffset)
				{
				case 1:
					bufLength = 2;
					break;
				case 2:
					bufLength = 4;
					break;
				case 3:
					bufLength = 8;
					break;
				}
			}
			if (m_DataLeftInCurrentSegment <= 0 && !DataAvailableInOraBuf())
			{
				GetDataFromNetwork();
			}
			dataBuffer = null;
			offset = 0;
			if (m_DataLeftInCurrentSegment >= bufLength)
			{
				if (!IgnoreData)
				{
					dataBuffer = m_currentSegmentArray;
					offset = m_positionInCurrentSegment;
				}
				m_positionInCurrentSegment += bufLength;
				m_DataLeftInCurrentSegment -= bufLength;
			}
			else
			{
				if (!IgnoreData)
				{
					dataBuffer = new byte[bufLength];
				}
				Read(dataBuffer, 0, bufLength);
			}
			return result;
		}

		private void GetDataFromNetwork()
		{
			if (m_currentOB != null)
			{
				for (int i = 0; i < m_currentOB.the_ByteSegments_Count; i++)
				{
					if (m_currentOB.the_ByteSegments[i].m_bInUseByTTCLayer)
					{
						m_currentOB = null;
						break;
					}
				}
			}
			if (m_oraBufWriter.m_lengthForDataSegment > 0)
			{
				m_oraBufWriter.FlushData();
			}
			if (m_bHoldOBTemporarily && m_currentOB != null)
			{
				m_tempOBList.Add(m_currentOB);
				m_currentOB = null;
			}
			if (m_currentOB == null)
			{
				m_currentOB = m_oraBufWriter.m_oracleComm.OraBufPool.Get(m_oraBufWriter.m_oracleComm.SDU, m_oraBufWriter.m_oracleComm, bReceive: true);
			}
			else
			{
				m_currentOB.ReInit(forReceive: true);
			}
			if (m_readerStream.Read(m_currentOB, out var _, out var _) == 0 || m_currentOB.the_ByteSegments == null || m_currentOB.the_ByteSegments_Count <= 0)
			{
				throw new Exception("Error: No data returned from Network Layer.");
			}
			m_currentArrSegments = m_currentOB.the_ByteSegments;
			m_segmentCount = m_currentOB.the_ByteSegments_Count;
			m_currentSegmentIndex = 0;
			m_currentSegment = m_currentArrSegments[m_currentSegmentIndex++];
			m_currentSegmentArray = m_currentSegment.Array;
			m_positionInCurrentSegment = m_currentSegment.Offset;
			m_DataLeftInCurrentSegment = m_currentSegment.Count;
			if (!m_bParsingColumnData || m_currentSegment.m_bInUseByTTCLayer)
			{
				return;
			}
			if (m_oraArrSegWithColRowInfo.Length <= m_oraArrSegWithColRowInfoIndex)
			{
				OraArraySegment[] array = new OraArraySegment[m_oraArrSegWithColRowInfo.Length * 2];
				for (int j = 0; j < m_oraArrSegWithColRowInfoIndex; j++)
				{
					array[j] = m_oraArrSegWithColRowInfo[j];
				}
				m_oraArrSegWithColRowInfo = array;
			}
			m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++] = m_currentSegment;
			m_currentOB = null;
			m_currentSegment.m_bInUseByTTCLayer = true;
		}

		internal bool DataAvailableInOraBuf()
		{
			bool result = false;
			if (m_currentSegment != null)
			{
				if (m_DataLeftInCurrentSegment > 0)
				{
					result = true;
				}
				else
				{
					bool flag = false;
					while (!flag)
					{
						if (m_DataLeftInCurrentSegment > 0)
						{
							flag = true;
							result = true;
						}
						else if (m_currentSegmentIndex < m_segmentCount)
						{
							m_currentSegment = m_currentArrSegments[m_currentSegmentIndex++];
							m_currentSegmentArray = m_currentSegment.Array;
							if (m_bParsingColumnData && !m_currentSegment.m_bInUseByTTCLayer)
							{
								if (m_oraArrSegWithColRowInfo.Length <= m_oraArrSegWithColRowInfoIndex)
								{
									OraArraySegment[] array = new OraArraySegment[m_oraArrSegWithColRowInfo.Length * 2];
									for (int i = 0; i < m_oraArrSegWithColRowInfoIndex; i++)
									{
										array[i] = m_oraArrSegWithColRowInfo[i];
									}
									m_oraArrSegWithColRowInfo = array;
								}
								m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++] = m_currentSegment;
								m_currentOB = null;
								m_currentSegment.m_bInUseByTTCLayer = true;
							}
							m_positionInCurrentSegment = m_currentSegment.Offset;
							m_DataLeftInCurrentSegment = m_currentSegment.Count;
						}
						else
						{
							flag = true;
						}
					}
				}
			}
			return result;
		}

		internal int GetData(byte[] userBuffer, int offset, int length)
		{
			int num = 0;
			if (m_DataLeftInCurrentSegment > 0)
			{
				num = (int)((length <= (int)m_DataLeftInCurrentSegment) ? length : m_DataLeftInCurrentSegment);
				if (userBuffer != null)
				{
					Buffer.BlockCopy(m_currentSegmentArray, m_positionInCurrentSegment, userBuffer, offset, num);
				}
				else if (m_bMarkStartOffsetForColData)
				{
					m_bMarkStartOffsetForColData = false;
					if (!m_currentSegment.m_bInUseByTTCLayer)
					{
						if (m_oraArrSegWithColRowInfo.Length <= m_oraArrSegWithColRowInfoIndex)
						{
							OraArraySegment[] array = new OraArraySegment[m_oraArrSegWithColRowInfo.Length * 2];
							for (int i = 0; i < m_oraArrSegWithColRowInfoIndex; i++)
							{
								array[i] = m_oraArrSegWithColRowInfo[i];
							}
							m_oraArrSegWithColRowInfo = array;
						}
						m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex++] = m_currentSegment;
						m_currentOB = null;
						m_currentSegment.m_bInUseByTTCLayer = true;
					}
					m_colDataStartOffset[m_colDataStartOffsetIndexToUpdate] = m_positionInCurrentSegment;
					m_indexOfOASArray[m_colDataStartOffsetIndexToUpdate] = m_oraArrSegWithColRowInfoIndex - 1;
				}
				else if (m_bAccumulateByteSegments)
				{
					m_dataSegments.Add(new ArraySegment<byte>(m_currentSegmentArray, m_positionInCurrentSegment, num));
				}
				m_positionInCurrentSegment += num;
				m_DataLeftInCurrentSegment -= num;
			}
			return num;
		}

		internal void StartAccumulatingRowData()
		{
			if (m_DataLeftInCurrentSegment <= 0 && !DataAvailableInOraBuf())
			{
				GetDataFromNetwork();
			}
		}

		internal void UpdateOASMaxRow(int lastRowNum)
		{
			if (m_oraArrSegWithColRowInfoIndex <= 0 || m_oraArrSegWithColRowInfo[m_oraArrSegWithColRowInfoIndex - 1] == null)
			{
				return;
			}
			int num = m_oraArrSegWithColRowInfoIndex - 1;
			m_oraArrSegWithColRowInfo[num].m_maxRowNum = lastRowNum;
			if (num <= 0)
			{
				return;
			}
			for (int num2 = num - 1; num2 >= 0; num2--)
			{
				if (-1 == m_oraArrSegWithColRowInfo[num2].m_maxRowNum)
				{
					m_oraArrSegWithColRowInfo[num2].m_maxRowNum = lastRowNum;
				}
				else if (m_oraArrSegWithColRowInfo[num2].m_maxRowNum < lastRowNum)
				{
					break;
				}
			}
		}

		internal void StopAccumulatingRowData()
		{
			m_dataSegments = null;
			m_currentOB = null;
		}

		internal void StartAccumulatingMyData(List<ArraySegment<byte>>[] rowDataSegments, int rowCounter)
		{
			m_bAccumulateByteSegments = true;
			if (rowDataSegments != null && rowDataSegments.Length > rowCounter)
			{
				m_dataSegments = rowDataSegments[rowCounter];
				if (m_dataSegments == null)
				{
					m_dataSegments = new List<ArraySegment<byte>>();
					rowDataSegments[rowCounter] = m_dataSegments;
				}
				else
				{
					m_dataSegments.Clear();
				}
			}
			else
			{
				m_dataSegments = new List<ArraySegment<byte>>();
				rowDataSegments[rowCounter] = m_dataSegments;
			}
		}

		internal bool StartAccumulatingColumnData(List<List<ArraySegment<byte>>> rowDataSegments, int rowCounter)
		{
			bool result = false;
			m_bAccumulateByteSegments = true;
			if (rowDataSegments != null && rowDataSegments.Count > rowCounter)
			{
				m_dataSegments = rowDataSegments[rowCounter];
				if (m_dataSegments == null)
				{
					m_dataSegments = new List<ArraySegment<byte>>();
					rowDataSegments[rowCounter] = m_dataSegments;
				}
				else
				{
					m_dataSegments.Clear();
				}
			}
			else
			{
				m_dataSegments = new List<ArraySegment<byte>>();
				result = true;
			}
			return result;
		}

		internal void StartAccumulatingColumnData(List<ArraySegment<byte>> dataSegments)
		{
			if (dataSegments == null)
			{
				dataSegments = new List<ArraySegment<byte>>();
			}
			else
			{
				dataSegments.Clear();
			}
			m_bAccumulateByteSegments = true;
			m_dataSegments = dataSegments;
		}

		internal void StopAccumulatingColumnData()
		{
			m_bAccumulateByteSegments = false;
			m_dataSegments = null;
		}
	}
}
